﻿using DataType;
using DataType.Actions;
using DataType.CustomEnumType;
using DataType.JudgeResults;
using DataType.MessageType;
using MapCalclator;
using OprsSimulator.OprAttributes;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OprsSimulator.Operators
{
    public class CruisingMissileOpr : IOperator, ICommonAttris, IMoveAttris, IReconnaissanceAttris, IStateAttris, IAttackAttris
    {
        //ICommonAttris
        private int obj_id;
        private string name;
        private Color color;
        private OprType type;
        private OprSubType sub_type;
        private int value;
        private int blood;
        private int max_blood;

        public int ObjID { get => obj_id; }
        public string Name { get => name; }

        public Color Color { get => color; }

        public OprType Type { get => type; }

        public OprSubType Subtype { get => sub_type; }

        public int Value { get => value; }

        public int Blood { get => blood; set => blood = value; }

        public int MaxBlood { get => max_blood; }
        //IMoveAttris
        private int basic_speed;
        private MoveStateType move_state;
        private int cur_hex;
        private float cur_pos;
        private int speed;
        private int move_to_stop_remain_time;
        private bool can_to_move;
        private bool flag_force_stop;
        private bool stop;
        private List<int> move_path;
        private int tire;
        private int tire_accumulate_time;
        private bool on_board;
        private int car;
        private int launcher;
        private int get_on_remain_time;
        private List<int> get_on_partner_id;
        private int get_off_remain_time;
        private List<int> get_off_partner_id;
        private int change_state_remain_time;
        private MoveStateType target_state;

        public int BasicSpeed { get => basic_speed; }

        public MoveStateType MoveState { get => move_state; set => move_state = value; }
        public int CurHex { get => cur_hex; set => cur_hex = value; }
        public float CurPos { get => cur_pos; set => cur_pos = value; }
        public int Speed { get => speed; set => speed = value; }
        public int MoveToStopRemainTime { get => move_to_stop_remain_time; set => move_to_stop_remain_time = value; }
        public bool CanToMove { get => can_to_move; set => can_to_move = value; }
        public bool FlagForceStop { get => flag_force_stop; set => flag_force_stop = value; }
        public bool Stop { get => stop; set => stop = value; }
        public List<int> MovePath { get => move_path; set => move_path = value; }
        public int Tire { get => tire; set => tire = value; }
        public int TireAccumulateTime { get => tire_accumulate_time; set => tire_accumulate_time = value; }
        public bool OnBoard { get => on_board; set => on_board = value; }
        public int Car { get => car; set => car = value; }
        public int Launcher { get => launcher; set => launcher = value; }
        public int GetOnRemainTime { get => get_on_remain_time; set => get_on_remain_time = value; }
        public List<int> GetOnPartnerId { get => get_on_partner_id; set => get_on_partner_id = value; }
        public int GetOffRemainTime { get => get_off_remain_time; set => get_off_remain_time = value; }
        public List<int> GetOffPartnerId { get => get_off_partner_id; set => get_off_partner_id = value; }
        public int ChangeStateRemainTime { get => change_state_remain_time; set => change_state_remain_time = value; }
        public MoveStateType TargetState { get => target_state; set => target_state = value; }
        //IReconnaissanceAttris
        private Dictionary<OprSubType, int> observe_distance;
        private List<int> see_enemy_bop_ids;
        public Dictionary<OprSubType, int> ObserveDistance { get => observe_distance; }

        public List<int> SeeEnemyBopIDs { get => see_enemy_bop_ids; set => see_enemy_bop_ids = value; }
        //IStateAttris
        private bool stack;
        private bool keep;
        private int keep_remain_time;
        private bool lose_control;
        private int alive_remain_time;
        public bool Stack { get => stack; set => stack = value; }
        public bool Keep { get => keep; set => keep = value; }
        public int KeepRemainTime { get => keep_remain_time; set => keep_remain_time = value; }
        public bool LoseControl { get => lose_control; set => lose_control = value; }
        public int AliveRemainTime { get => alive_remain_time; set => alive_remain_time = value; }

        //IAttackAttris
        private bool a1;
        private List<WeaponType> carry_weapon_ids = new List<WeaponType>();
        private Dictionary<BulletType, int> remain_bullet_nums = new Dictionary<BulletType, int>();
        private Dictionary<BulletType, int> remain_bullet_nums_bk = new Dictionary<BulletType, int>();
        private bool guide_ability;
        private int weapon_cool_time;
        private int weapon_unfold_time;
        private int weapon_unfold_state;
        public bool A1 { get => a1; }

        public List<WeaponType> CarryWeaponIDs { get => carry_weapon_ids; }

        public Dictionary<BulletType, int> RemainBulletNums { get => remain_bullet_nums; set => remain_bullet_nums = value; }
        public Dictionary<BulletType, int> RemainBulletNumsBK { get => remain_bullet_nums_bk; set => remain_bullet_nums_bk = value; }

        public bool GuideAbility { get => guide_ability; }

        public int WeaponCoolTime { get => weapon_cool_time; set => weapon_cool_time = value; }
        public int WeaponUnfoldTime { get => weapon_unfold_time; set => weapon_unfold_time = value; }
        public int WeaponUnfoldState { get => weapon_unfold_state; set => weapon_unfold_state = value; }

        public void SetUp(OperatorMsg operatorMsg)
        {
            //ICommonAttris
            obj_id = operatorMsg.obj_id;
            name = operatorMsg.name;
            color = (Color)operatorMsg.color;
            type = (OprType)operatorMsg.type;
            sub_type = (OprSubType)operatorMsg.sub_type;
            value = operatorMsg.value;
            blood = operatorMsg.blood;
            max_blood = operatorMsg.max_blood;
            //IMoveAttris
            basic_speed = operatorMsg.basic_speed;
            move_state = (MoveStateType)operatorMsg.move_state;
            cur_hex = operatorMsg.cur_hex;
            cur_pos = operatorMsg.cur_pos;
            speed = operatorMsg.speed;
            move_to_stop_remain_time = operatorMsg.move_to_stop_remain_time;
            can_to_move = operatorMsg.can_to_move;
            flag_force_stop = operatorMsg.flag_force_stop;
            stop = operatorMsg.stop;
            move_path = operatorMsg.move_path;
            tire = operatorMsg.tire;
            tire_accumulate_time = operatorMsg.tire_accumulate_time;
            on_board = operatorMsg.on_board;
            car = operatorMsg.car ?? -1;
            launcher = operatorMsg.launcher ?? -1;
            get_on_remain_time = operatorMsg.get_on_remain_time;
            get_on_partner_id = operatorMsg.get_on_partner_id;
            get_off_remain_time = operatorMsg.get_off_remain_time;
            get_off_partner_id = operatorMsg.get_off_partner_id;
            change_state_remain_time = operatorMsg.change_state_remain_time;
            target_state = (MoveStateType)operatorMsg.target_state;
            //IReconnaissanceAttris
            if (operatorMsg.observe_distance == null)// 如果无值，按规则赋值
            {
                observe_distance = new Dictionary<OprSubType, int>
                {
                    {OprSubType.Tank, 2},
                    {OprSubType.IFV, 2},
                    {OprSubType.Infantry, 2},
                    {OprSubType.Artillery, 2},
                    {OprSubType.UGV, 2},
                    {OprSubType.Drone, 0},
                    {OprSubType.Helicopter, 0},
                    {OprSubType.CruisingMissile, 0},
                };
            }
            else
            {
                foreach (var od in operatorMsg.observe_distance)
                {
                    observe_distance.Add((OprSubType)od.Key, od.Value);
                }
            }
            see_enemy_bop_ids = operatorMsg.see_enemy_bop_ids ?? new List<int>();
            //IStateAttris
            stack = operatorMsg.stack;
            keep = operatorMsg.keep;
            keep_remain_time = operatorMsg.keep_remain_time;
            lose_control = operatorMsg.lose_control;
            alive_remain_time = operatorMsg.alive_remain_time;
        }
        public void UpdataStandaloneAttris(List<IJudgeResult> judge_results, Map map)
        {
            foreach (IJudgeResult judge_result in judge_results)// 根据裁决结果更新属性
            {
                if (judge_result.ActionType == ActionType.Shoot)// 直瞄射击
                {
                    if (judge_result.ObjID == obj_id)// 巡飞弹不能作为射击目标，即只能是主动射击
                    {
                        UpdataShootAttris(judge_result);// 已经执行了射击动作，成不成功都修改属性
                    }
                }
                else if (!judge_result.IsSuccess) continue;// 没成功，跳过
                else if (judge_result.ActionType == ActionType.GetOff)// 下车
                {                  
                    UpdataGetOffAttris(judge_result);// 下车裁决结果更新
                }
                else
                {
                    if (judge_result.ObjID != obj_id) continue;// 不是本算子，跳过

                    if (judge_result.ActionType == ActionType.Move) UpdataMoveAttris(judge_result, map);// 机动裁决结果更新
                    else if (judge_result.ActionType == ActionType.StopMove) UpdataStopMoveAttris(judge_result);// 停止机动裁决结果更新
                }
            }
            PutForwardObservation(map);// 更新持续性动作，如机动和各种倒计时等
        }
        public void UpdateAssociatedAttris(List<IOperator> oprs, List<IOperator> passengers, Map map)
        {
            if (!on_board) UpdataSeeEnemyAttris(oprs, map);// 下车之后更新观察敌方算子属性
            GetOnAndOffMonitor(oprs);// 下车时检查车辆是否被压制
        }
        public Dictionary<int, List<ActionMsg>> ConfirmValidActions(List<OperatorMsg> oprs, CityMsg[] cities, Map map, ShootJudgeTable shootJudgeTable, List<IOperator> passengers)
        {
            Dictionary<int, List<ActionMsg>> individualValidActions = new Dictionary<int, List<ActionMsg>>();// 保存本算子的全部合法动作，用于返回

            // 判断算子是否能机动
            bool move_flag = true;  // 能够机动的标识
            List<ActionMsg> move_action = new List<ActionMsg>();// 新建机动动作
            if (speed > 0) move_flag = false;   //未停下的算子不可机动
            if (move_flag)// 如果可以机动
            {
                move_action.Add(new ActionMsg { type = (int)ActionType.Move, obj_id = obj_id });// 设置动作类型、算子id
                individualValidActions.Add((int)ActionType.Move, move_action);// 动作集合添加进合法动作以该动作类型为键的值中
            }

            // 判断能否停止机动
            if (speed > 0)// 正在机动
            {
                List<ActionMsg> stop_move_action = new List<ActionMsg>();// 新建停止机动动作
                stop_move_action.Add(new ActionMsg { type = (int)ActionType.StopMove, obj_id = obj_id });// 设置动作类型、算子id
                individualValidActions.Add((int)ActionType.StopMove, stop_move_action);// 动作集合添加进合法动作以该动作类型为键的值中
            }

            // 判断算子是否能射击
            List<ActionMsg> shoot_action = new List<ActionMsg>();// 新建直瞄射击动作
            if (see_enemy_bop_ids.Count > 0)// 如果有观察到的敌方
            {
                for (int i = 0; i < see_enemy_bop_ids.Count(); i++)// 遍历
                {
                    int enemy_id = see_enemy_bop_ids[i];// 保存敌方id
                    // 逐个判断是否能对enemy_id的敌方算子实施射击
                    OperatorMsg enemy;
                    foreach (OperatorMsg oper in oprs)
                    {
                        if (oper.obj_id == enemy_id)// 用id找到敌方算子
                        {
                            enemy = oper;// 记录敌方算子
                            foreach (WeaponType weapon_id in carry_weapon_ids)// 携带的每个武器都判断一遍
                            {

                                bool can_see = map.CanSeeTerrain(type, (OprType)enemy.type, cur_hex, enemy.cur_hex, (OprSubType)enemy.sub_type, observe_distance, (MoveStateType)enemy.move_state);// 判断是否可以看见目标
                                int distance = map.GetDistance(cur_hex, enemy.cur_hex);// 获得与目标的距离
                                int attack_level = shootJudgeTable.CalcAttackLevel(can_see, remain_bullet_nums, weapon_id, (OprType)enemy.type, distance, blood);// 获取攻击等级
                                if (attack_level > 0)// 如果攻击等级大于0
                                {
                                    shoot_action.Add(
                                        new ActionMsg// 创建射击动作，并添加
                                        {
                                            type = (int)ActionType.Shoot,// 动作类型
                                            obj_id = obj_id,// 算子id
                                            target_obj_id = enemy_id,// 射击目标id
                                            weapon_id = (int)weapon_id,// 武器id
                                            attack_level = attack_level// 攻击等级
                                        }
                                        );
                                }
                            }
                        }
                    }
                }
            }
            if (shoot_action.Count > 0)// 如果有可以执行的射击动作
            {
                individualValidActions.Add((int)ActionType.Shoot, shoot_action);// 动作集合添加进合法动作以该动作类型为键的值中
            }

            return individualValidActions;
        }
        private void PutForwardObservation(Map map)
        {
            // 修改机动属性
            if (speed > 0 && move_path.Count > 0)// 速度大于0，有机动路径
            {
                float percetage = (float)speed / 3.6f / (float)map.Width;// 计算一个step移动了多远（speed是km/h，除3.6得到m/s，除六角格宽度（单位为米））
                cur_pos += percetage;
                if (cur_pos >= 1)  // 到达了下一格
                {
                    cur_pos = 0;
                    cur_hex = move_path[0];// 修改位置
                    move_path.RemoveAt(0);// 修改机动路径
                    if (move_path.Count <= 0)  // 如果机动完成，转为停止
                    {
                        speed = 0;
                    }
                    else// 还有没走完的机动路径
                    {
                        speed = (int)(basic_speed / map.GetHexCosts(cur_hex / 100, cur_hex % 100, MoveMode.Fly)[move_path[0]]);// 计算速度（基础速度除通行代价）
                    }
                }
            }

            //下车倒计时
            if (get_off_remain_time > 0)
            {
                if (get_off_partner_id.Count <= 0)  //车辆算子被压制，导致get_off_partner_id为空
                {
                    get_off_remain_time = 0;
                }
                else
                {
                    get_off_remain_time--;
                    if (get_off_remain_time <= 0)// 倒计时结束
                    {
                        launcher = get_off_partner_id[0];// 记录发射算子
                        on_board = false;// 不在车上
                        car = -1;// 修改所属车辆id
                        get_off_partner_id.Clear();// 清除车辆算子id
                        alive_remain_time = 1201;// 巡飞弹存活时间1200秒
                        //下车完成初始化机动属性
                        can_to_move = true;// 可机动
                        stop = true;// 静止
                    }
                }
            }
            // 存活时间倒计时
            if (alive_remain_time > 0)
            {
                alive_remain_time--;
                if (alive_remain_time <= 0)// 存活时间结束
                {
                    blood = 0;// 结束生命
                }
            }
        }
        private void UpdataGetOffAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.GetOff) return;

            GetOffJudgeResult getOffJudgeResult = (GetOffJudgeResult)judge_result;// 强转为下车裁决结果类型
            if (getOffJudgeResult.TargetObjID != obj_id) return;// 如果要下车的不是本算子，跳过
            get_off_partner_id.Add(getOffJudgeResult.ObjID);// 添加下车的车辆id  添加的是动作主体ObjID：重型战车
            get_off_remain_time = 76;// 下车倒计时75秒
            cur_hex = getOffJudgeResult.CurHex;// 更新算子位置为车辆当前的位置
        }
        private void UpdataMoveAttris(IJudgeResult judge_result, Map map)
        {
            if (judge_result.ActionType != ActionType.Move)
            {
                return;
            }

            MoveJudgeResult moveJudgeResult = (MoveJudgeResult)judge_result;// 强转为机动裁决结果类型
            //修改算子属性
            speed = (int)(basic_speed / map.GetHexCosts(cur_hex / 100, cur_hex % 100, MoveMode.Fly)[moveJudgeResult.MovePath[0]]);// 修改速度，基础速度除通行代价
            move_path = moveJudgeResult.MovePath;// 保存机动路径
        }
        private void UpdataStopMoveAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.StopMove)
            {
                return;
            }
            // 没有强制停止机动惩罚，所以没有使用flag_force_stop，所以停止机动的裁决结果修改与其他算子有所区别
            if (cur_pos > 0)// 如果在机动中
            {
                //move_path = new List<int> { move_path[0] };
                if (move_path.Count > 1)// 如果还有机动路径
                {
                    move_path = move_path.Take(1).ToList();// 保留当前机动的目标六角格，其他的删去
                }
            }
            else// 如果没有在机动中
            {
                if (move_path.Count > 0) move_path.Clear();// 如果还有机动路径，清空
            }
        }
        private void UpdataShootAttris(IJudgeResult judge_result)
        {
            if (judge_result.ActionType != ActionType.Shoot || judge_result.ObjID != obj_id)
            {
                return;
            }
            blood = 0;// 射击完就自毁
        }
        private void UpdataSeeEnemyAttris(List<IOperator> oprs, Map map)
        {
            if (observe_distance == null) return;// 如果观察距离属性没有数据，跳过

            if (see_enemy_bop_ids == null) see_enemy_bop_ids = new List<int>();// 清空，等待存入新的数据
            else see_enemy_bop_ids.Clear();
            for (int i = 0; i < oprs.Count; i++)// 遍历态势中的算子
            {
                // 取属性
                if (!typeof(ICommonAttris).IsAssignableFrom(oprs[i].GetType()) ||
                    !typeof(IMoveAttris).IsAssignableFrom(oprs[i].GetType())) continue;

                Color enemy_color = (Color)oprs[i].GetType().GetProperty("Color").GetValue(oprs[i]);
                OprType enemy_type = (OprType)oprs[i].GetType().GetProperty("Type").GetValue(oprs[i]);
                int enemy_hex = (int)oprs[i].GetType().GetProperty("CurHex").GetValue(oprs[i]);
                OprSubType enemy_sub_type = (OprSubType)oprs[i].GetType().GetProperty("Subtype").GetValue(oprs[i]);
                MoveStateType enemy_move_state = (MoveStateType)oprs[i].GetType().GetProperty("MoveState").GetValue(oprs[i]);

                if (color == enemy_color) continue;// 如果是己方算子，跳过
                // 可视则添加
                if (map.CanSeeTerrain(type, enemy_type, cur_hex, enemy_hex, enemy_sub_type, observe_distance, enemy_move_state))// 如果可以看见
                {
                    see_enemy_bop_ids.Add(oprs[i].ObjID);// 添加
                }
            }
        }
        private void GetOnAndOffMonitor(List<IOperator> oprs)
        {
            ////上车时检测车辆算子是否被压制
            //if (get_on_partner_id == null) get_on_partner_id = new List<int>();
            //if (get_on_partner_id.Count > 0 && get_on_remain_time > 0)
            //{
            //    foreach (IOperator op in oprs)
            //    {
            //        if (get_on_partner_id.Contains(op.ObjID))
            //        {
            //            if (!typeof(IMoveAttris).IsAssignableFrom(op.GetType()) || !typeof(ICommonAttris).IsAssignableFrom(op.GetType())) continue;

            //            bool opKeep = (bool)op.GetType().GetProperty("Keep").GetValue(op);
            //            if (opKeep)
            //            {
            //                get_on_partner_id.Remove(op.ObjID);
            //            }
            //        }
            //    }
            //}
            //下车时检测车辆算子是否被压制
            if (get_off_partner_id == null) get_off_partner_id = new List<int>();
            if (get_off_partner_id.Count > 0 && get_off_remain_time > 0)// 如果正在下车
            {
                foreach (IOperator op in oprs)
                {
                    if (get_off_partner_id.Contains(op.ObjID))// 找到车辆算子
                    {
                        if (!typeof(IMoveAttris).IsAssignableFrom(op.GetType()) || !typeof(ICommonAttris).IsAssignableFrom(op.GetType())) continue;

                        bool opKeep = (bool)op.GetType().GetProperty("Keep").GetValue(op);// 取属性
                        if (opKeep)// 如果车辆被压制
                        {
                            get_off_partner_id.Remove(op.ObjID);// 移除，中断下车
                        }
                    }
                }
            }
        }
    }
}
